/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frsoap_parse.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2015/08/31 by geyh                                 */
/*******************************************************************/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/xpath.h>
#include <libxml/parser.h>
#include <unistd.h>
#undef _GNU_SOURCE

#include "frcomm.h"
#include "frsoap_parse.h"


int frxml_detect(char *p_data_in, int i_data_len)
{
    int i_ret = 0;

    if(p_data_in == NULL || i_data_len < 5)
        return FR_FAIL;

    //"<?xml "
    i_ret = memcmp(p_data_in,"<?xml " ,6);
    if(i_ret != 0)
        return FR_FAIL;

    i_data_len -= 6;
    p_data_in += 6;

    //跳过空格
    while(*p_data_in == ' ' && i_data_len)
    {
        p_data_in++;
        i_data_len--;
    }
    if(i_data_len < 7)
        return FR_FAIL;

    //version
    i_ret = memcmp(p_data_in,"version",7);
    if(i_ret != 0)
        return FR_FAIL;

    i_data_len -= 7;
    p_data_in += 7;

    //跳过空格
    while(*p_data_in == ' ' && i_data_len)
    {
        p_data_in++;
        i_data_len--;
    }

    //等号
    if(*p_data_in != '=')
        return FR_FAIL;

    p_data_in++;
    i_data_len--;

    //跳过空格
    while(*p_data_in == ' ' && i_data_len)
    {
        p_data_in++;
        i_data_len--;
    }

    //版本号
    if (memcmp(p_data_in,"\"1.",3) != 0 && memcmp(p_data_in,"'1.",3) != 0)
        return FR_FAIL;

    p_data_in += 3;
    i_data_len -= 3;

    if(i_data_len < 2)
        return FR_FAIL;

    if (*p_data_in < '0' || *p_data_in > '9' || (*(p_data_in + 1) != '"' && *(p_data_in + 1) != '\''))
        return FR_FAIL;

    //?>结束
    p_data_in = (char *) memchr(p_data_in, '?', i_data_len);
    if(p_data_in == NULL || *(p_data_in + 1) != '>')
        return FR_FAIL;

    return FR_SUCC;
}


int frsoap_parse_req(char *p_data_in, int i_data_len, Frreport_body_data *p_st_body_data)
{
    xmlDocPtr p_st_doc = NULL;
    xmlNodePtr p_st_cur = NULL;
    xmlChar *p_content = NULL;
    char arr_name[1024];
    int i_ret = 0;

    if(p_data_in == NULL || i_data_len == 0 || p_st_body_data == NULL)
        return FR_FAIL;

    if(strcasestr(p_data_in, "Envelope") == NULL)
        return FR_SUCC;

    //查询soap体内容  解析过程不输出错误信息跟警告
    p_st_doc = xmlReadMemory(p_data_in, i_data_len, NULL, NULL, XML_PARSE_NOERROR|XML_PARSE_NOWARNING );
    if(p_st_doc == NULL)
        return FR_SUCC;

    //根节点
    p_st_cur = xmlDocGetRootElement(p_st_doc);
    if(p_st_cur == NULL)
        goto ERROR;

    p_st_cur = xmlFirstElementChild(p_st_cur);
    if(p_st_cur == NULL)
        goto ERROR;

    while(p_st_cur)
    {
        if(!xmlStrcmp(p_st_cur->name, (const xmlChar *)"Body"))
            break;

        p_st_cur = p_st_cur->next;
    }

    if(p_st_cur == NULL)
    {
        xmlFreeDoc(p_st_doc);
        return FR_SUCC;
    }

    p_st_cur = xmlFirstElementChild(p_st_cur);
    if(p_st_cur == NULL)
    {
        xmlFreeDoc(p_st_doc);
        return FR_SUCC;
    }

    //函数名
    i_ret = frreport_body_l7_add_str(p_st_body_data, "request.soap.function", (const char *)p_st_cur->name);
    if(i_ret == FR_FAIL)
    {

        xmlFreeDoc(p_st_doc);
        return FR_FAIL;
    }
    
    p_st_cur = xmlFirstElementChild(p_st_cur);
    if(p_st_cur == NULL)
    {
        xmlFreeDoc(p_st_doc);
        return FR_SUCC;
    }

    //参数
    while(p_st_cur!=NULL)
    {
        //参数名上报
        snprintf(arr_name, sizeof(arr_name), "request.soap.arg.%s", (const char *)p_st_cur->name);

        p_content = xmlNodeGetContent(p_st_cur);
        if(p_content)
        {
            i_ret = frreport_body_l7_add_str(p_st_body_data, arr_name, (const char *)p_content);
            xmlFree(p_content);
        }
        else
            i_ret = frreport_body_l7_add_str(p_st_body_data, arr_name, "\0");

        if(i_ret == FR_FAIL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_FAIL;
        }

        p_st_cur = p_st_cur->next;
    }

        //如果不存在
    xmlFreeDoc(p_st_doc);
    return FR_SUCC;

ERROR:
    xmlFreeDoc(p_st_doc);
    return FR_FAIL;
}

//
//FR_STATIC int __xmlnode_report(Frreport_body_data *p_st_body_data, xmlNodePtr p_st_node, int i_use_request)
//{
//    int i_ret = 0;
//    xmlNodePtr p_st_bro = NULL;
//    xmlNodePtr p_st_cur = NULL;
//    char arr_name[1024];
//
//    if(p_st_body_data == NULL || p_st_node == NULL)
//        return FR_FAIL;
//
//    p_st_cur = p_st_node;
//    while(p_st_cur->children)
//        p_st_cur = xmlFirstElementChild(p_st_cur);
//
//
//
//
//    return FR_SUCC;
//
//}


int frsoap_parse_resp(char *p_data_in, int i_data_len, Frreport_body_data *p_st_body_data, char **pp_code_string, char **pp_err_msg)
{
    xmlDocPtr p_st_doc = NULL;
    xmlNodePtr p_st_cur = NULL, p_st_child = NULL;
    char *p_content = NULL;
    char arr_name[1024];
    int i_ret = 0;
    char *p_code = NULL, *p_subcode = NULL, *p_code_string = NULL;

    if(p_data_in == NULL || i_data_len == 0 || p_st_body_data == NULL || pp_code_string == NULL || pp_err_msg == NULL)
        return FR_FAIL;

    if(strcasestr(p_data_in, "Envelope") == NULL)
        return FR_SUCC;

    //   查询soap体内容  解析过程不输出错误信息跟警告
    p_st_doc = xmlReadMemory(p_data_in, i_data_len, NULL, NULL, XML_PARSE_NOERROR|XML_PARSE_NOWARNING );
    if(p_st_doc == NULL)
        return FR_FAIL;

    //根节点
    p_st_cur = xmlDocGetRootElement(p_st_doc);
    if(p_st_cur == NULL)
        goto ERROR;

    p_st_cur = xmlFirstElementChild(p_st_cur);
    if(p_st_cur == NULL)
        goto ERROR;

    while(p_st_cur)
    {
        if(!xmlStrcmp(p_st_cur->name, (const xmlChar *)"Body"))
            break;

        p_st_cur = p_st_cur->next;
    }

    if(p_st_cur == NULL)
    {
        xmlFreeDoc(p_st_doc);
        return FR_SUCC;
    }

    p_st_cur = xmlFirstElementChild(p_st_cur);
    if(p_st_cur == NULL)
    {
        xmlFreeDoc(p_st_doc);
        return FR_SUCC;
    }

    //正常情况
    if(xmlStrcmp(p_st_cur->name, (const xmlChar *)"Fault") != 0)
    {
        //函数名
        i_ret = frreport_body_l7_add_str(p_st_body_data, "response.soap.function", (const char *)p_st_cur->name);
        if(i_ret == FR_FAIL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_FAIL;
        }
    
        p_st_cur = xmlFirstElementChild(p_st_cur);
        if(p_st_cur == NULL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_SUCC;
        }

        //参数
        while(p_st_cur!=NULL)
        {
            //参数名上报
            snprintf(arr_name, sizeof(arr_name), "response.soap.arg.%s", (const char *)p_st_cur->name);

            p_content = (char *)xmlNodeGetContent(p_st_cur);
            if(p_content)
            {
                i_ret = frreport_body_l7_add_str(p_st_body_data, arr_name, p_content);
                xmlFree(p_content);
                p_content = NULL;
            }
            else
                i_ret = frreport_body_l7_add_str(p_st_body_data, arr_name, "\0");

            if(i_ret == FR_FAIL)
                goto ERROR;

            p_st_cur = p_st_cur->next;
        }
    }
    else
    {
        //清除HTTP层返回信息
        if(*pp_code_string)
            frfree(*pp_code_string);

        *pp_code_string = NULL;

        if(*pp_err_msg)
            frfree(*pp_err_msg);

        *pp_err_msg = NULL;
        //code
        p_st_child = xmlFirstElementChild(p_st_cur);
        if(p_st_child == NULL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_SUCC;
        }

        while(p_st_child && xmlStrcmp(p_st_child->name, (const xmlChar *)"Code") != 0)
            p_st_child = p_st_child->next;

        if(p_st_child == NULL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_SUCC;
        }

        p_st_child = xmlFirstElementChild(p_st_child);
        if(p_st_child == NULL)
        {
            xmlFreeDoc(p_st_doc);
            return FR_SUCC;
        }

        p_code = (char *)xmlNodeGetContent(p_st_child);
        if(p_code == NULL)
            goto ERROR;

        p_st_child = p_st_child->next;

        while(p_st_child && xmlStrcmp(p_st_child->name, (const xmlChar *)"Subcode") != 0)
            p_st_child = p_st_child->next;

        if(p_st_child == NULL)
            goto ERROR;

        p_st_child = xmlFirstElementChild(p_st_child);
        if(p_st_child == NULL)
            goto ERROR;

        p_subcode = (char *)xmlNodeGetContent(p_st_child);
        if(p_subcode == NULL)
            goto ERROR;

        //p_code_string = code[subcode]
        p_code_string = (char *) frmalloc(strlen(p_code) + strlen(p_subcode) + 3);
        if(p_code_string == NULL)
            goto ERROR;

        snprintf(p_code_string, strlen(p_code) + strlen(p_subcode) + 3, "%s[%s]", p_code, p_subcode);
        xmlFree(p_code);
        p_code = NULL;
        xmlFree(p_subcode);
        p_subcode = NULL;
        //todo code string report

        //Reason
        p_st_child = xmlFirstElementChild(p_st_cur);
        if(p_st_child == NULL)
            goto ERROR;

        while(p_st_child && xmlStrcmp(p_st_child->name, (const xmlChar *)"Reason") != 0)
            p_st_child = p_st_child->next;

        if(p_st_child == NULL)
            goto ERROR;

        p_content = (char *)xmlNodeGetContent(p_st_child);

        *pp_code_string = p_code_string;
        *pp_err_msg = frstrdup((const char *) p_content);
        xmlFree(p_content);
    }

    //如果不存在
    xmlFreeDoc(p_st_doc);
    return FR_SUCC;

ERROR:
    if(p_code);
        xmlFree(p_code);

    if(p_subcode)
        xmlFree(p_subcode);

    if(p_content)
        xmlFree(p_content);

    xmlFreeDoc(p_st_doc);
    return FR_FAIL;
}


int frxml_parser_read(char *p_data_in, int i_data_len)
{
    xmlDocPtr p_st_doc = NULL;

    if(p_data_in == NULL || i_data_len == 0)
        return FR_FAIL;

    //查询soap体内容  解析过程不输出错误信息跟警告
    p_st_doc = xmlReadMemory(p_data_in, i_data_len, NULL, NULL, XML_PARSE_NOERROR|XML_PARSE_NOWARNING );
    if(p_st_doc == NULL)
        return FR_FAIL;

    xmlFreeDoc(p_st_doc);
    return FR_SUCC;
}
